package com.hl.payServer.core.wePay;



import com.hl.payServer.model.enums.WepayField;
import com.hl.payServer.security.MD5;
import com.hl.payServer.util.Jsons;
import com.hl.payServer.util.Maps;
import com.hl.payServer.util.http.Http;
import com.hl.payServer.util.http.Https;
import com.hl.payServer.util.xml.XmlReaders;
import tk.mybatis.mapper.util.StringUtil;

import java.util.Map;
import java.util.TreeMap;

public abstract class Component {

    protected Wepay wepay;

    protected Component(Wepay wepay){
        this.wepay = wepay;
    }

    protected Map<String, Object> doPost(final String url, final Map<String, String> params){
        String requestBody = Maps.toXml(params);
        String resp = Http.post(url).ssl().body(requestBody).request();
        Map<String, Object> respMap = XmlReaders.readXMLString("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"+resp.replaceAll("(\\r|\\n)", ""));
        doVerifySign(respMap);
        return respMap;
    }

    protected <T> T doPost(final String url, final Map<String, String> params, Class<T> respClazz){
        String requestBody = Maps.toXml(params);
        String resp = Http.post(url).ssl().body(requestBody).request();
        Map<String, Object> respMap = XmlReaders.readXMLString("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"+resp.replaceAll("(\\r|\\n)", ""));
        doVerifySign(respMap);
        return Jsons.DEFAULT.fromJson(Jsons.DEFAULT.toJson(respMap), respClazz);
    }
    protected String doPostObBill(final String url, final Map<String, String> params){
        String requestBody = Maps.toXml(params);
        String resp = Http.post(url).ssl().body(requestBody).request();
        return resp;
    }

    protected <T> T doHttpsPost(final String url, final Map<String, String> params, Class<T> respClazz){
        String requestBody = Maps.toXml(params);
        String resp = Https.post(url,true).body(requestBody).ssLSocketFactory(wepay.getSslSocketFactory()).request();
        Map<String, Object> respMap = XmlReaders.readXMLString(resp.replaceAll("(\\r|\\n)", ""));
        doVerifySign(respMap);
        return Jsons.DEFAULT.fromJson(Jsons.DEFAULT.toJson(respMap), respClazz);
    }

    /**
     * 构建配置参数
     * @param params 参数
     */
    protected void buildConfigParams(final Map<String, String> params){
        params.put(WepayField.APP_ID, wepay.getAppId());
        params.put(WepayField.MCH_ID, wepay.getMchId());
    }

    /**
     * 构建签名参数
     * @param params 支付参数
     */
    protected void buildSignParams(final Map<String, String> params) {
        String sign = doSign(params);
        put(params, WepayField.SIGN, sign);
    }

    /**
     * 支付请求前签名
     * @param params 参数(已经升序, 排出非空值和sign)
     * @return MD5的签名字符串(大写)
     */
    protected String doSign(final Map<String, String> params) {
        StringBuilder signing = new StringBuilder();

        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (StringUtil.isNotEmpty(entry.getValue())){
                signing.append(entry.getKey()).append('=').append(entry.getValue()).append("&");
            }
        }
        // append key
        signing.append("key=").append(wepay.getAppKey());
        // md5
        return MD5.generate(signing.toString(), false).toUpperCase();
    }

    /**
     * 校验参数
     * @param data 待校验参数
     * @return 校验成功返回true，反之false
     */
    protected Boolean doVerifySign(final Map<String, ?> data) {
        String actualSign = String.valueOf(data.get(WepayField.SIGN));
        Map<String, String> signingMap = filterSignParams(data);
        String expectSign = doSign(signingMap);
        return expectSign.equals(actualSign);
    }

    /**
     * 过滤签名参数(升序，排出空值，sign)
     * @param params 待校验参数
     * @return 过滤后的参数
     */
    protected Map<String, String> filterSignParams(final Map<String, ?> params) {
        Map<String, String> validParams = new TreeMap<String, String>();

        for (Map.Entry<String, ?> param : params.entrySet()){
            if (WepayField.SIGN.equals(param.getKey())
                    || param.getValue() == null
                    || "".equals(String.valueOf(param.getValue()))){
                continue;
            }
            validParams.put(param.getKey(), String.valueOf(param.getValue()));
        }

        return validParams;
    }

    protected void putIfNotEmpty(final Map<String, String> map, String field, String paramValue) {
        if (StringUtil.isNotEmpty(paramValue)){
            map.put(field, paramValue);
        }
    }

    protected void put(final Map<String, String> map, String field, String paramValue){
        map.put(field, paramValue);
    }
}
